/*****************************************************************************/
/**
 * *
 * * @file hello.c
 * *
 * * Linux driver, only for test.
 * *
 * * <pre>
 * * MODIFICATION HISTORY:
 * *
 * * Ver   Who    Date   	Changes
 * * ----- ---- ---------- -------------------------------------------------------
 * * 0.01  abu  04/10/2020 Created
 * * </pre>
 * *
 * *------------------------------------------------------------------------------
 * * Author: abu	E-mail:	abu_liu@aliyun.com
 * *				Blog:	https://blog.csdn.net/ClamerKorallen
 * *				Gitee:	https://gitee.com/abu_liu
 * *------------------------------------------------------------------------------
 * *
 * ******************************************************************************/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>

#define HELLO_MAJOR_DEVNUM 200
#define HELLO_MINOR_DEVNUM 2
#define HELLO_MODULE_NAME Hello_world

static char read_buffer[100];
static char write_buf[100];
static char kernel_data[] = {"Kernel data!"};

static int __init hello_init(void);
static void __exit hello_exit(void);
static int hello_open(struct inode *inode, struct file *filp);
static ssize_t hello_read(struct file *filp, char __user *buf,
                            size_t cnt, loff_t *offt);
static ssize_t hello_write(struct file *filp, const char __user *buf,
                    size_t cnt, loff_t *offt);
static int hello_release(struct inode *inode, struct file *filp);


static struct file_operations hello_fops = {
  .owner = THIS_MODULE,
  .open = hello_open,
  .read = hello_read,
  .write = hello_write,
  .release = hello_release,
};

static int __init hello_init(void)
{
  int retvalue;

  retvalue = register_chrdev(HELLO_MAJOR_DEVNUM, "HELLO_MODULE_NAME", &hello_fops);
  if(retvalue <0){
    printk(KERN_INFO "Module hello register failed\n");
  }
  else
  	printk(KERN_INFO "HEllo world enter\n");

  return 0;
}

static void __exit hello_exit(void)
{
  unregister_chrdev(HELLO_MAJOR_DEVNUM, "HELLO_MODULE_NAME");
	printk(KERN_INFO "Hello world exit\n");
}

static int hello_open(struct inode *inode, struct file *filp){
  printk(KERN_INFO "we are now at %s", __func__);
  return 0;
}


static ssize_t hello_read(struct file *filp, char __user *buf,
                            size_t cnt, loff_t *offt){

	int retvalue;
	
	printk(KERN_INFO "we are now at %s", __func__);


	memcpy(read_buffer, kernel_data, sizeof(kernel_data));
	retvalue = copy_to_user(buf, read_buffer, cnt);
	if(retvalue == 0)
		printk("kernel data read success\r\n");
	else
		printk("kernel data read failed\r\n");
  
  return 0;
}

static ssize_t hello_write(struct file *filp, const char __user *buf,
                    size_t cnt, loff_t *offt){
	int retvalue;
	printk(KERN_INFO "we are now at %s", __func__);
	
	retvalue = copy_from_user(write_buf, buf, sizeof(cnt));
	if(retvalue == 0)
		printk("kernel received data:%s\r\n", write_buf);
	else
		printk("kernel received data failed\r\n");

	return 0;
}


static int hello_release(struct inode *inode, struct file *filp){
  printk(KERN_INFO "we are now at %s", __func__);
  return 0;
}


module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("Abu Liu");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple hello world module");
MODULE_ALIAS("a simple test");
